Skip to content

feat(i18n): finish the seven-language site (de, es, ko, pt) and fix the menu that clipped them - #193

Merged
chaxus merged 5 commits into
mainfrom
i18n-seven-languages
Aug 23, 2026
Merged

feat(i18n): finish the seven-language site (de, es, ko, pt) and fix the menu that clipped them#193
chaxus merged 5 commits into
mainfrom
i18n-seven-languages

Conversation

@chaxus

@chaxus chaxus commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Continues #192, which auto-merged before these five commits were pushed — so they had no PR of their own until now.

#192 landed the generator and Japanese. This adds the remaining four languages and fixes what shipping seven of them exposed.

German, Spanish, Korean, Portuguese

18 landing pages + the homepage + the help centre each; changelog and Embed API reference reuse the English source with a notice, as the other locales do. 154 generated pages from 7 content directories.

Code changes beyond the LOCALES table: none. A language is one directory under content/.

The bug that mattered most

The hand-written Chinese homepage linked to /editor?locale=zh-CN&new=docx. The generated template dropped the parameter, so a visitor who picked a language on the site landed in an editor that guessed one from browser settings — and the same would have been true for every new locale. The app resolves ?locale= before cookie / localStorage / navigator.language and passes it to the vendor editor, so this is the single link that decides whether "the site is in Japanese" also means "the editor is in Japanese".

Verified per locale, in a production build: /ja/ → New Word → /editor?locale=ja<html lang="ja"> → OnlyOffice frame lang=ja → toolbar reading ファイル / ホーム / 挿入. Same for de, es, ko, pt, zh-CN. Pinned in landing-pages.test.ts, reverse-checked.

Persian removed, so the numbers mean one thing

fa was the eighth shell locale and the one the site could not honour: the vendor editor ships ar, he and ur but no fa, so a Persian visitor got a fully Persian page around an English toolbar — and the stylesheets still use physical properties (31 padding-left and friends), so the pages would have laid out LTR anyway. The table is gone; RTL_LANGUAGES stays as an empty list with the reason written beside it.

README now says 7 languages end to end (pages, app UI and editor all follow the one you pick), with the vendor's 45 as a separate fact.

Two things the seventh language made visible

  • The menu clipped its own languages. The trigger was 104px, sized when the longest endonym was "Deutsch". The component clips inside its shadow root and sizes the panel to the trigger, so "Português" was cut twice over: Portug… in the list, and in the trigger the word sat on the caret. Now 132px — measured, not guessed: test/e2e/language-menu.spec.ts opens all seven locales and fails if any label is clipped (reverse-checked at 104px).
  • The homepages kept the browser's 8px body margin. landing.css always reset it; home.css never did, because the homepage builds its own chrome. Invisible on white, obvious in dark mode. Now pinned in design-contract and checked on rendered pages.

Also

llms-full.txt walks every page under public/, so the translations pushed it from ~97 KB to 680 KB of the same facts seven times over. It now covers the English pages and says where the mirrors are; /llms.txt still links them. sitemap.xml carries all 154 URLs.

CLAUDE.md gains the rule this exposed: the language list lives in four places (SHELL_LOCALES, the generator's LOCALES, content/<locale>/, README) describing the same thing, so they move together — and a locale is only worth adding if the vendor has a matching editor locale.

🤖 Generated with Claude Code

chaxus and others added 5 commits August 23, 2026 10:16
Two more content directories, no code changes beyond the LOCALES table:
18 landing pages, the homepage and the help centre in each language, with
the changelog and the Embed API reference reusing the English source and
saying so, as the other locales do.

The site is now English, Chinese, Japanese, German and Spanish -- 110
generated pages from 5 content directories, where the same coverage in
hand-written HTML would have been 110 files to keep in step. README's
"8 interface languages" line now separates the three numbers that were
being conflated: 5 for the translated site, 8 for the app UI, 45 for the
editor itself.

sitemap.xml and llms.txt list the new mirrors; the language trigger grew
from 76px to 104px, which is what "Deutsch" and "Español" need (at 76 it
rendered "Deuts").

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The hand-written Chinese homepage linked to /editor?locale=zh-CN&new=docx.
The generated template dropped the parameter, so a visitor who had picked
a language on the site landed in an editor that guessed one from browser
settings instead -- and the same would have been true for every new
locale.

The app resolves ?locale= before cookie, localStorage and
navigator.language, and passes it on to the vendor editor, so this is the
one link in the chain that decides whether "the site is in Japanese"
also means "the editor is in Japanese".

Verified end to end per locale: /ja/ -> New Word -> /editor?locale=ja ->
<html lang="ja"> -> the OnlyOffice frame loaded with lang=ja; same for de,
es and zh-CN. Pinned in landing-pages.test.ts (reverse-checked: removing
the parameter turns those cases red).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two more content directories: 18 landing pages, the homepage and the help
centre in each, with the changelog and the Embed API reference reusing the
English source and saying so.

The site is now English, Chinese, Japanese, German, Spanish, Korean and
Portuguese -- 154 generated pages from 7 content directories. That is
every shell locale the app UI has except Persian, which needs the
stylesheets moved to logical properties first (and whose editor UI would
fall back to English: the vendor ships ar, he and ur, but no fa).

Also fixed while adding pt: the history strings added a few commits ago
had slipped into European Portuguese ("ficheiro", "Transferir",
"Definições") while the rest of the pt table is Brazilian ("arquivo").

README now says 7 for the site.

Verified per locale: /ko/ and /pt/ -> New Word -> /editor?locale=… ->
<html lang> -> the OnlyOffice frame with a matching lang.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Persian was the eighth shell locale and the one the site could not honour:
the vendor editor ships ar, he and ur but no fa, so a Persian visitor got
a fully Persian page around an English editor toolbar. The site's
stylesheets also still use physical properties (31 padding-left and
friends across four files), so the pages would have laid out
left-to-right regardless.

Rather than ship half of it, the fa table is removed and SHELL_LOCALES is
the seven the site is actually translated into. RTL_LANGUAGES stays as an
empty list with the reason written next to it: the machinery is fine, the
prerequisites are not, and adding ar/he/ur later is a data change plus a
logical-properties pass.

The three numbers README was juggling now agree: 7 languages end to end
(pages, app UI and editor all follow the one you pick), and 45 locales in
the vendor editor as a separate fact about the engine.

`?locale=fa` now falls back to English cleanly -- pinned in i18n.test.ts,
and checked in the built app: <html lang="en">, dir="ltr", editor lang=en.

CLAUDE.md gains the rule this exposed: the language list exists in four
places (SHELL_LOCALES, the generator's LOCALES, content/<locale>/ and the
README) and they describe the same thing, so they move together -- and a
locale is only worth adding if the vendor has a matching editor locale.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two things the seventh language made visible, plus one it made expensive.

**The menu clipped its own languages.** The trigger's width was 104px, a
number picked when the longest endonym was "Deutsch". The component clips
with overflow:hidden inside its shadow root and sizes the dropdown panel
to the trigger, so "Português" was cut in two places at once: "Portug…"
in the list, and in the trigger the word sat on top of the caret. Width
is now 132px -- measured rather than guessed, because
test/e2e/language-menu.spec.ts opens all seven locales and fails if any
label is clipped. Reverse-checked at 104px: the pt case goes red.

**The homepages kept the browser's 8px body margin.** landing.css always
reset it; home.css never did, because the homepage builds its own chrome
and does not load landing.css. Invisible on a white page, obvious in dark
mode as a frame of backdrop around the whole site. design-contract now
requires the reset in both stylesheets, and the e2e case checks the
rendered value on a homepage, a translated homepage, a satellite page and
/history.

**llms-full.txt was seven times longer than it needed to be.** It walks
every page under public/, so the translations pushed it from ~97 KB to
680 KB of the same facts in seven languages -- duplication that costs a
model context and tells it nothing new. It now covers the English pages
and says, at the top, where the mirrors are; /llms.txt still links them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@chaxus
chaxus enabled auto-merge (rebase) August 23, 2026 02:18
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying document with  Cloudflare Pages  Cloudflare Pages

Latest commit: 536f397
Status: ✅  Deploy successful!
Preview URL: https://5b6138b9.document-7hm.pages.dev
Branch Preview URL: https://i18n-seven-languages.document-7hm.pages.dev

View logs

@chaxus
chaxus merged commit 1fd1d45 into main Aug 23, 2026
18 checks passed
@chaxus
chaxus deleted the i18n-seven-languages branch August 23, 2026 02:23
@chaxus
chaxus restored the i18n-seven-languages branch August 23, 2026 03:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant